﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WW.NActiveRecord.ConnectionAdapters.SqlServer;
using WW.NActiveRecord.Internal.Utils;

namespace WW.NActiveRecord.Internal.SqlFragments
{
    abstract class WhereFragment {
        //计算当前where片断
        internal abstract WhereFragmentResult Calculate();

        internal static WhereFragment NewSqlWhereFragment(string sql, IEnumerable<NamedParameter> parameters)
        {
            return new SqlWhereFragment(sql, parameters);
        }
        internal static WhereFragment NewFieldWhereFragment(NamedParameter parameter)
        {
            return new FieldWhereFragment(parameter);
        }

        class SqlWhereFragment : WhereFragment {
            internal readonly string sql;

            //{parameterName:parameter}
            internal readonly IDictionary<string, NamedParameter> parameters = new Dictionary<string, NamedParameter>();

            internal SqlWhereFragment(string sql, IEnumerable<NamedParameter> parameters) {
                this.sql = sql;
                foreach (var parameter in parameters) {
                    this.parameters.Add(parameter.Name, parameter);
                }
            }

            internal override WhereFragmentResult Calculate() {
                return new WhereFragmentResult(sql, parameters.Values.Select(x => new KeyValuePair<string, object>(x.Name, x.Value)).ToArray());
            }
        }

        class FieldWhereFragment : WhereFragment {
            private readonly string name;
            private readonly NamedParameter parameter;

            public FieldWhereFragment(NamedParameter parameter) {
                this.name = parameter.Name;
                this.parameter = parameter;
            }

            internal override WhereFragmentResult Calculate() {
                object value = parameter.Value;
                if (value == null) {
                    return new WhereFragmentResult(string.Format("{0} IS NULL", name));
                } else if (typeof(ICollection).IsAssignableFrom(value.GetType())) {
                    return new WhereFragmentResult(string.Format("{0} IN ({1})", name, SqlDb.QuoteParameterValue(value)));
                } else {
                    return new WhereFragmentResult(string.Format("{0}=@{1}", name, name), new KeyValuePair<string, object>(parameter.Name, parameter.Value));
                }
            }
        }
    }

    internal class WhereFragmentResult {
        internal readonly string sql;
        internal readonly IDictionary<string, object> parameters;
        public WhereFragmentResult(string sql, params KeyValuePair<string, object>[] parameters) {
            this.sql = sql;
            this.parameters=parameters.ToDictionary(item => item.Key, item => item.Value);
        }
    }
}